#pragma once
#include <iostream>
#include <vector>
#include <queue>
#include <pthread.h>
#include <unistd.h>
using namespace std;

#include "Mythread.hpp"
#include "SmartMutex.hpp"
#include "Log.hpp"

const size_t defaultthreadnum = 5;

class ThreadData
{
public:
    ThreadData(const string &threadname) : _threadname(threadname) {}

    string _threadname;
};

template <class T>
class ThreadPool
{
private:
    void ThreadWait(const string& name)
    {
        pthread_cond_wait(&_cond, &_mutex);
        log(Debug, "线程: %s开始休眠\n", CSTR(name));
    }

    void ThreadWake()
    {
        pthread_cond_signal(&_cond);
    }

public:
    ThreadPool(size_t threadnum = defaultthreadnum) : _threadnum(threadnum)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);

        for (int i = 0; i < _threadnum; i++)
        {
            string threadname = "thread-" + to_string(i + 1);
            _threads.emplace_back(threadname, bind(&ThreadPool<T>::ThreadRun, this, placeholders::_1), ThreadData(threadname));
            log(Debug, "线程: %s创建完毕\n", CSTR(threadname));
        }
    }

    void ThreadRun(ThreadData &td)
    {
        while (true)
        {
            T t;
            {
                SmartMutex smartmutex(&_mutex);
                while (_q.empty())
                {
                    ThreadWait(td._threadname);
                }
                // 取任务
                {
                    t = _q.front();
                    _q.pop();
                    log(Info, "线程: %s取到任务 : %s\n", CSTR(td._threadname), CSTR(t()));
                }
            }

            // while (_q.empty()) // 有问题的代码
            // {
            //     ThreadWait();
            // }
            // // 取任务
            // cout << td._threadname << "取任务" << endl;
            // T t;
            // {
            //     SmartMutex smartmutex(&_mutex);
            //     t = _q.front();
            //     _q.pop();
            // }

            // 执行任务
            t();
            log(Info, "线程: %s执行任务 : %s\n", CSTR(td._threadname), CSTR(t()));
        }

        // while(true)
        // {
        //     cout << "thread run..." << endl;
        //     sleep(1);
        // }
    }

    void Push(const T &in)
    {
        SmartMutex smartmutex(&_mutex);
        _q.push(in);
        ThreadWake();
        log(Info, "主线程: 派发任务 : %s\n", CSTR(_q.front()()));
    }

    void Start()
    {
        for (auto &thread : _threads)
        {
            thread.Start();
        }
    }

    void Wait()
    {
        for (auto &thread : _threads)
        {
            thread.Join();
        }
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

private:
    queue<T> _q;
    vector<Thread<ThreadData>> _threads;
    size_t _threadnum;

    pthread_mutex_t _mutex;
    pthread_cond_t _cond;
};
